package teamone;

import robocode.ScannedRobotEvent;
import robocode.util.Utils;

import java.awt.geom.*;
import java.util.*;

public class Battle {
		
	protected static void circularShooting(SimpleDrone MyRobot, ScannedRobotEvent e, double bulletPower){
	        //set bullet power
		 	bulletPower = Math.min(bulletPower, MyRobot.getEnergy());
	        //my current position
	        double myX = MyRobot.getX(), myY = MyRobot.getY();
	        
	        /*
	         * getHeadingRadians() returns the direction that the robot's body is facing, in radians. 
	         * The value returned will be between 0 and 2 * PI (is excluded). 
	         * 0 means North, PI / 2 means East, PI means South, and 3 * PI / 2 means West. 
	         * 
	         * e.getBearingRadians() returns the angle to the robot, relative to your robot's heading, in radians. -PI < getRobotBearingRadians() <= PI 
	        */
	        double enemyAbsoluteBearing = MyRobot.getHeadingRadians() + e.getBearingRadians();
	        
	        //calculate the absolute position of the enemy on the battlefield
	        double enemyX = MyRobot.getX() + e.getDistance() * Math.sin(enemyAbsoluteBearing);
	        double enemyY = MyRobot.getY() + e.getDistance() * Math.cos(enemyAbsoluteBearing);
	        
	        //get the direction that the enemy robot is facing, in radians.
	        double enemyHeading = e.getHeadingRadians();
	        //calculate the change for the enemy robot
	        double enemyHeadingChange = enemyHeading - MyRobot.oldEnemyHeading;
	        //now the current enemy heading will become the old enemy heading for the next iteration 
	        MyRobot.oldEnemyHeading = enemyHeading;
	        //get the speed of the enemy
	        double enemySpeed = e.getVelocity();
	        
	        //get the dimensions of the battle field
	        double battleFieldHeight = MyRobot.fieldHeight, battleFieldWidth = MyRobot.fieldWidth;
	        double predictedX = enemyX, predictedY = enemyY;
	        //
	        double delta = 0;
	        //in robocode, bullets move with a velocity of: 20 - (3 * bulletPower)
	        double bulletSpeed = 20.0 - 3.0 * bulletPower;
	        /* while the bullet travels the distance from my current position to the enemy robot predict where the enemy will be 
	         * Stop when the bullet has reached the enemy robot or when the enemy is very close to a wall. 
	        */
	        while((++delta) * bulletSpeed < Point2D.Double.distance(myX, myY, predictedX, predictedY)){             
	                //Iteratively predict the position of the enemy robot
	                predictedX += Math.sin(enemyHeading) * enemySpeed;
	                predictedY += Math.cos(enemyHeading) * enemySpeed;
	                enemyHeading += enemyHeadingChange;
	                //if the enemy robot is going to be closer then 18 pixels to one of the four walls
	                if(     predictedX < 18.0 
	                        || predictedY < 18.0
	                        || predictedX > battleFieldWidth - 18.0
	                        || predictedY > battleFieldHeight - 18.0){
	         
	                        /* for X: if 0 <= predictedX <= 18 then choose 18
	                         *                if (battleFieldWidth - 18.0) <= predictedX <= battleFieldWidth then choose (battleFieldWidth - 18.0)
	                        */      
	                        predictedX = Math.min(Math.max(18.0, predictedX), battleFieldWidth - 18.0);     
	                        //same for Y
	                        predictedY = Math.min(Math.max(18.0, predictedY), battleFieldHeight - 18.0);
	                        //terminate the while loop
	                        break;
	                }
	        }
	        
	        //convert from rectangular coordinates (x,y) to polar coordinates (r, theta) and return the angle theta in radians 
	        double theta = Utils.normalAbsoluteAngle(Math.atan2(predictedX - MyRobot.getX(), predictedY - MyRobot.getY()));
	         
	        //point the radar at the enemy robot by turning the radar from its current bearing to the enemy's bearing
	        MyRobot.setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - MyRobot.getRadarHeadingRadians()));
	        //point the gun at the enemy robot by turning the gun from its current heading to the enemy's predicted heading (theta) 
	        MyRobot.setTurnGunRightRadians(Utils.normalRelativeAngle(theta - MyRobot.getGunHeadingRadians()));
	        //fire the gun
	        if(MyRobot.getGunHeat() == 0){
	        	MyRobot.fire(bulletPower);
	        }
	    }
	 
	 public static void circleEnemyAndShoot(SimpleDrone MyRobot, ScannedRobotEvent e){
			if (MyRobot.isTeammate(e.getName())){
				return;
			} else {

				// enemy detected
				// calculate the size of my team
				int noTeammates = 0;
				String[] teammates = MyRobot.getTeammates();
				if (teammates != null) {
					noTeammates = teammates.length;
				}
				// add me to the total number of teammates
				noTeammates++;
				// calculate the radius of the circle around the enemy
				MyRobot.radiusCircleEnemy = (MyRobot.circleSectorLength * noTeammates)
						/ (2 * Math.PI);
				if (MyRobot.radiusCircleEnemy < 150)
					MyRobot.radiusCircleEnemy = 190;

				if ((e.getDistance() >= (MyRobot.radiusCircleEnemy + 25))
						|| (e.getDistance() <= (MyRobot.radiusCircleEnemy - 25))) {
					Point2D.Double myShootingLocation;
					myShootingLocation = getMyShootingLocation(MyRobot, e,
							MyRobot.radiusCircleEnemy, noTeammates);
					// move to the shooting location
					Movement.move(MyRobot, myShootingLocation.getX(), myShootingLocation.getY());
				}
				
				// Stay at right angles to the opponent
				MyRobot.setTurnRight(e.getBearing() + 90);

				// If the bot has small energy drop,
				// assume it fired
				double changeInEnergy = MyRobot.previousEnergy - e.getEnergy();
				if (changeInEnergy > 0 && changeInEnergy <= 3) {
					// Dodge!
					MyRobot.movementDirection = (-1) * MyRobot.movementDirection;
					MyRobot.setAhead((e.getDistance() / 4 + 25) * MyRobot.movementDirection);
				}
				// Fire directly at target
				circularShooting(MyRobot, e, 1);

				// Track the energy level
				MyRobot.previousEnergy = e.getEnergy();
			}
		}
	 
	// this method returns a location around the enemy from where my robot
		// starts shooting
		protected static Point2D.Double getMyShootingLocation(SimpleDrone MyRobot, ScannedRobotEvent e,
				double radiusCircleEnemy, double noTeammates) {

			// get enemy's position
			double enemyAbsoluteBearing = MyRobot.getHeadingRadians()
					+ e.getBearingRadians();
			// calculate the absolute position of the enemy on the battlefield
			double enemyX = MyRobot.getX() + e.getDistance()
					* Math.sin(enemyAbsoluteBearing);
			double enemyY = MyRobot.getY() + e.getDistance()
					* Math.cos(enemyAbsoluteBearing);

			// get my number in the team
			int myRobotNumber = getBotNumber(MyRobot.getName());

			double theta = 2 * Math.PI;// angle in radians
			theta = myRobotNumber * (theta / noTeammates);

			// convert from polar coordinates (theta, r) to rectangular coordinates
			// (x,y)
			double x = Math.cos(theta) * radiusCircleEnemy;
			double y = Math.sin(theta) * radiusCircleEnemy;
			// add to the enemy location to get the absolute coordinates on the
			// battle field
			x += enemyX;
			y += enemyY;
			Point2D.Double myShootingLocation = new Point2D.Double(x, y);

			return myShootingLocation;

			// TO DO: check for overflow of battle field dimensions + dynamically
			// calculate the radius
			/*
			 * if(e.getDistance()>250){ //move towards the enemy
			 * Scanning.moveTo(this, getX(), getY(), enemyX-140, enemyY-140);
			 * //onEnemyTarget = true; } else if(e.getDistance()<150) { //move away
			 * from the enemy Scanning.moveTo(this, getX(), getY(), enemyX-100,
			 * enemyY-100); }
			 */
		}
	 
		static public int getBotNumber(String name) {
			String n = "0";
			int low = name.indexOf("(") + 1;
			int hi = name.lastIndexOf(")");
			if (low >= 0 && hi >= 0) {
				n = name.substring(low, hi);
			}
			return Integer.parseInt(n);
		}	
		
	 public static void battleEnemy(SimpleDrone MyRobot){
		 while(MyRobot.battleMode){
			 MyRobot.turnRadarLeft(360);
		 }
	 }
}
